#ifndef RSUCOMM_H
#define RSUCOMM_H

#include <QObject>
#include <QTcpSocket>

class RsuComm : public QObject
{
    Q_OBJECT

public:
    explicit RsuComm(QObject *parent = 0);
    ~RsuComm();

public:
    void openRsu(const QString &host, quint16 port);
    void closeRsu();

public:
    /*!
    * \brief 命令执行成功
    */
    const static int ERR_SUCCESS = 0;

    /*!
     * \brief 超时，RSU设备无响应
     */
    const static int ERR_RSU_OVERTIME = -100;

    /*!
     * \brief 传入参数错误
     */
    const static int ERR_RSU_API_INPUT_ERROR = -1000;

    /*!
     * \brief 设备未打开
     */
    const static int ERR_RSU_NOT_OPENED = -1001;

    /*!
     * \brief 其他错误
     */
    const static int ERR_RSU_OTHER = -2000;

public:
    int initRsuRq(char *Time, int BSTInterval, int TxPower, int PLLChannelID);
    int initPrimRq(char *BeaconID, char *Time, int Profile, int MandApplicationlist,
                   char *MandApplication, int Profilelist);
    int rsuInfoRq();

public:
    static quint8 transBaudToCode(long baud);

public:
    // 模拟测试用
    void mockRawFrameData(QByteArray &frame);

protected:
    static quint8 getXOR(const QByteArray &data);
    bool processDataRead(const QByteArray &dataRead, QByteArray *pExpectedFrame, quint8 nExpectedFrameType);
    bool processRawFrame(QByteArray &frame, QByteArray *pExpectedFrame, quint8 nExpectedFrameType);
    void processFrame(quint8 nFrameIndex, quint8 nFrameType, QByteArray &frame);

    /*!
     * \brief 封装帧数据，进行转义并增加帧头、帧序号、校验码、帧尾。
     * \param 待封装数据。
     */
    void wrapFrame(QByteArray &data);

    /*!
     * \brief 封装并发送帧数据。
     * \param date: 待发送数据
     * \return
     */
    int wrapAndSendFrame(QByteArray &data);

    /*!
     * \brief 以阻塞式方式读取数据并解包，注意如果执行时读到了如搜寻OBU等返回数据，期待的操作尚未返回，则会执行失败或错误。
     * \param pExpectedFrame: 传回要读取的帧
     * \param nExpectedFrameType: 等待读取的帧类型
     * \param nTimeOut: 等待超时事件
     * \return
     */
    int readAllAndUnwrapFrame(QByteArray *pExpectedFrame, quint8 nExpectedFrameType, int nTimeOut);

private:
    /*!
     * \brief 在日志中记录读到的数据，用于跟踪调试。
     * \param dataRead: 读到的数据
     * \param flag: 读取来源标记
     */
    void logBytesRead(const QByteArray &dataRead, const QString &flag);

protected:
    QTcpSocket m_tcpSocket;
    /*!
     * \brief m_dataRead: 已都到原始数据。
     */
    QByteArray m_dataRead;

    /*!
     * \brief m_sHostAddr: 天线IP地址。
     */
    QString m_sHostAddr;

    /*!
     * \brief m_nHostPort: 天线监听端口。
     */
    quint16 m_nHostPort;

protected:
    /*!
     * \brief m_bReadInBlockMode: 是否处于阻塞式读取状态，在这一状态，readReady事件中不读数据。
     */
    bool m_bReadInBlockMode;

protected:
    quint8 getRSCTL()
    {
        if (m_frameIndex>7)
        {
            m_frameIndex=0;
        }
        quint8 n=0x80+m_frameIndex;
        m_frameIndex++;
        return n;
    }
    quint8 m_frameIndex;

protected:
    static int getCmdGroupLen(int cmdCount, const char *cmdGroup)
    {
        int n=0;
        for (int i=0; i<cmdCount; i++)
        {
            n+=(cmdGroup[n]+1);
        }
        return n;
    }

public:
    static const int RSU_TYPE_CHENGGU=0;
    static const int RSU_TYPE_SHOWLINX=1;

public:
    void configRsuType(int nRsuType)
    {
        m_nRsuType=nRsuType;
    }
    int getRsuType() const
    {
        return m_nRsuType;
    }

protected:
    int m_nRsuType;

signals:
    void newFrameArrived(quint8 nFrameIndex, quint8 nFrameType, const QByteArray &frame);
    void stateChanged(QAbstractSocket::SocketState);

protected slots:
    void socketConnected();
    void socketDisconnected();
    void socketBytesWritten(qint64 bytes);
    void socketReadyRead();
    void socketStateChanged(QAbstractSocket::SocketState socketState);
    void socketError(QAbstractSocket::SocketError socketError);

protected slots:
    void tryReconnect();

public slots:
};

#endif // RSUCOMM_H
